home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Symantec Visual Cafe for Java 2.5
/
symantec-visual-cafe-2.5-database-dev-edition.iso
/
Visual Cafe Pro v1.0
/
SOURCE.BIN
/
Grid.java
< prev
next >
Encoding:
Amiga
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1997-06-19
|
124.0 KB
|
4,394 lines
/*
* Grid.java 1.0 12 Jan 1997
*
* Copyright (c) 1996 Krumel & Associates, Inc. All Rights Reserved.
*
* This software is provided as is. Krumel & Associates shall not be liable
* for any damages suffered by licensee as a result of using, modifying or
* distributing this software or its derivatives.
*/
package symantec.itools.db.awt;
import java.awt.*;
import java.util.*;
import java.io.*;
/**
* A spreadsheet style control.<p>
*
* All column and row numbers are one relative.<p>
*
* The Grid supports column and row headings. The row headings may be blank or
* autonumbered based on a user defined base number.<p>
*
* The Grid provides support for a toolbar along the bottom row to the right
* of the horizontal scrollbar. Any type of component may be added to the toolbar
* or pre-defined buttons may be added using the available addXXXXButton methods.<p>
*
* To increase the modularity of the grid, events and exceptions are passed to
* an EventHandler object when set. Event IDs have been defined for the table
* and cells. Additional events are generated by the toolbar components and
* forwarded to the EventHandler as well. Of course the tradional event model
* of JDK 1.0.2 is also supported but tends to make GUI code functional.
* All lighting, inserts, gotos, ... are performed by the EventHandler. <p>
*
* To further increase modularity, data is kept in DataSources. A default
* DataSource if one is not defined that simply stores the data in a Matrix
* instance. If a RelationView is specified in the constructor, then a special
* DataSource is created to drive the Grid off of the database query.<p>
*
* A number of APIs are defined to allow the grid color, font, and other visual
* styles to be effected.
*
* @version 1.0 12 Jan 1997
* @author Andy Krumel - Krumel & Associates, Inc
*/
public class Grid extends Panel /* implements Runnable */ {
boolean autoRedraw = true;
boolean onSolaris;
Button button;
Panel toolbar;
Panel bottomPanel;
Vector toolbarComponents = new Vector();
TvEventHandler eventHandler;
Matrix cells;
Matrix colHeadings;
Matrix cellAttributes; //cell hints
Matrix headingAttributes; //col heading hints
int preferredRowCount = 10;
int splitters[];
boolean fillLastColumn;
Scrollbar vsb;
Scrollbar hsb;
int cursor = Frame.DEFAULT_CURSOR;
long clickTime;
int topRow;
int leftCol = 1;
int dragColumn = -1;
int xDragLast = -1;
boolean isDragging;
int headingHeight;
int cellHeight;
int clickMargin = 5;
int currentCursor = Frame.DEFAULT_CURSOR;
Image im;
Graphics gg;
int height;
int width;
int vsbPosition;
int hsbPosition;
long scrollbarTimer;
boolean fetchMode = false;
DataSource dataSource;
DataSource headingSource;
DefaultDataSource rowHeadingSource;
CellHints hints;
TableCell currSelectedCell = null;
TableCell currCaptureCell = null;
TableCell defaultCell;
boolean tabbed;
symantec.itools.db.pro.RelationViewMetaData rvmd;
//-----------------------------------------------------------------------------
// Column Heading Variables
//-----------------------------------------------------------------------------
int rowHeadingWidth = 30;
CellHints rowHeadingHints;
boolean autoCreate = true;
int rowHeadingLabelStyle = BLANK;
int firstNumber = 1; //used for autonumbering
TableCell headingCell; //the default row heading cell
TableCell currHeadingCell; //the one currently being pressed
//this is null if not in use
TableCell cornerCell; //the default row heading cell
//row heading styles
/**
* Autonumber row heading style
*/
public final static int AUTONUMBER = 0;
/**
* Blank row headings - the default
*/
public final static int BLANK = 1;
/**
* User defined style - not currently supported
*/
public final static int USER_DEFINED = 2;
/**
* TableCell type as returned by TableCell.type()
*/
public final static Integer TABLE_CELL = new Integer(1);
/**
* The corner cell type as returned by TableCell.type()
*/
public final static Integer CORNER_CELL = new Integer(2);
/**
* Column heading type as returned by TableCell.type()
*/
public final static Integer COLUMN_HEADING = new Integer(3);
/**
* Row heading cell type as returned by TableCell.type()
*/
public final static Integer ROW_HEADING = new Integer(4);
/**
* default append row toolbar button label
*/
public static String appendRowLabel = "Append";
/**
* default delete row toolbar button label
*/
public static String deleteRowLabel = "Delete";
/**
* default insert row toolbar button label
*/
public static String insertRowLabel = "Insert";
/**
* default goto row toolbar button label
*/
public static String gotoRowLabel = "Goto >>>";
/**
* default save row toolbar button label
*/
public static String saveLabel = "Save";
/**
* default restart row toolbar button label
*/
public static String restartLabel = "Restart";
/**
* default undo row toolbar button label
*/
public static String undoRowLabel = "Undo";
/**
* default undelete row toolbar button label
*/
public static String undeleteRowLabel = "Undelete";
//-----------------------------------------------------------------------------
// Event IDs
//-----------------------------------------------------------------------------
/**
* Grid level event for when grid got focus
*/
public final static int GOT_FOCUS = Event.GOT_FOCUS;
/**
* Grid level event for when grid lost focus
*/
public final static int LOST_FOCUS = Event.LOST_FOCUS;
/**
* Grid level event for when row inserted
*/
public final static int INSERT = 3; //insert row above specified row
/**
* Grid level event for when rpw is deleted
*/
public final static int DELETE = 4; //delete specified row
/**
* Grid level event for when row is appended
*/
public final static int APPEND = 5; //add row to end of data
/**
* Grid level event for when row is undeleted
*/
public final static int UNDELETE = 7;
/**
* Base cell level event ID
*/
public final static int CELL_EVENT = 50;
/**
* Cell level event for when cell is button an pushed down
*/
public final static int BUTTON_DOWN_EVENT = CELL_EVENT;
/**
* Cell level event for when cell is button a mouse is released over button
*/
public final static int BUTTON_UP_EVENT = CELL_EVENT + 1;
/**
* Button depressed but mouse moved off button then back on
*/
public final static int BUTTON_FLICKER_DOWN_EVENT = CELL_EVENT + 2;
/**
* Button depressed but mouse moved off button
*/
public final static int BUTTON_FLICKER_UP_EVENT = CELL_EVENT + 3;
/**
* User requested the most recent changes to be undone and the latest
* committed data be reset
*/
public final static int UNDO_CELL_EVENT = CELL_EVENT + 4;
/**
* Cell level event for when cell gets focus
*/
public final static int GOT_CELL_FOCUS = CELL_EVENT + 5;
/**
* Cell level event for when cell loses focus
*/
public final static int LOST_CELL_FOCUS = CELL_EVENT + 6;
/**
* User performed action to change contents of a cell (like a key press)
*/
public final static int CELL_CONTENT_CHANGE = CELL_EVENT + 7;
/**
* Cell level event for when key is pressed in cell
*/
public final static int CELL_KEY_DOWN = CELL_EVENT + 8;
/**
* Cell level event for when key is released in cell
*/
public final static int CELL_KEY_UP = CELL_EVENT + 9;
/**
* Cell level event for when mouse is released in cell
*/
public final static int CELL_MOUSE_UP = CELL_EVENT + 10;
/**
* Cell level event for when mouse is pushed down in cell
*/
public final static int CELL_MOUSE_DOWN = CELL_EVENT + 11;
/**
* Cell level event for when mouse is dragged in cell
*/
public final static int CELL_MOUSE_DRAG = CELL_EVENT + 12;
/**
* Double click within cell
*/
public final static int CELL_MOUSE_DOUBLE = CELL_EVENT + 13;
//-----------------------------------------------------------------------------
// Constant IDs
//-----------------------------------------------------------------------------
/**
* Time to register a double click (in milliseconds).
*/
public final static long CLICKTHRESHOLD = 250;
/**
* Left-justify constant.
*/
public final static int LEFT = 0;
/**
* Center-justify constant.
*/
public final static int CENTER = 1;
/**
* Right-justify constant.
*/
public final static int RIGHT = 2;
//Cell line styles - not implemented yet
final static int NO_LINE = 0;
final static int THIN_LINE = 1;
final static int THICK_LINE = 2;
final static int DASHED_LINE = 3;
//Cell vertical align styles
final static int TOP = 0;
// public final static int CENTER = 1; //already defined
final static int BOTTOM = 2;
static TableCell defaultHeadingCell_ = new ButtonCell();
static boolean defaultsInitialized = false;
//static initializers don't work in Explorer so we use a function
static void initDefaults() {
if (!defaultsInitialized) {
defaultHeadingCell_.setCoordinates(new Coordinate(0,0));
defaultHeadingCell_.type(TableCell.ROW_HEADING);
defaultsInitialized = true;
}
}
/**
* Default constructor for new Grid.
*/
public Grid() {
this(0,0);
}
/**
* Constructs a new Grid with the specified number of columns.
* @param cols the number of columns
*/
public Grid(int cols) {
this(0,cols);
}
/**
* Constructs a new Grid with the preferred height based on
* specified number of rows.
* @param rows the number of rows to show
*/
public Grid(long rows) {
this(rows, 0);
}
/**
* Constructs a new Grid with the spcified number of columns
* and whether multiple row selection allowed.
* @param rows the number of rows to show
* @param cols the number of columns
*/
public Grid(long rows, int cols) {
dataSource = new DefaultDataSource(this);
assignDefaults();
dataSource.setDefaultData();
createColumns(cols);
setupAutonumbering(1);
setBackground(Color.white);
try
{
for( int i=0; i < rows; i++)
{
appendRow();
}
for(int i=0; i< cols;i++)
{
setHeading( "Column:"+(i+1), i+1, 10);
}
} catch( Exception e)
{System.out.println( "EXCEPTION " + e);}
preferredRowCount = (int)rows;
}
/**
* Constructs a new Grid with the spcified number of columns
* and whether multiple row selection allowed, and background color.
* @param cols the number of columns
* @bg Color instance for background color
*/
public Grid(int cols, Color bg) {
dataSource = new DefaultDataSource(this);
assignDefaults();
dataSource.setDefaultData();
createColumns(cols);
setupAutonumbering(1);
setBackground(bg);
}
/**
* Constructs a new Grid using the specified RelationView. Grid will
* automatically setup the columns.
* @param relView the RelationView on which to drive the Grid
* @exception symjava.sql.SQLException Thrown when the Grid cannot
* be successfully setup due to a database problem
*/
public Grid(symantec.itools.db.pro.RelationView relView)
throws symjava.sql.SQLException
{
this(relView, null,0);
}
public Grid(symantec.itools.db.pro.RelationView relView,int coltoshow)
throws symjava.sql.SQLException
{
this(relView, null, coltoshow);
}
symantec.itools.db.pro.RelationView relation,
master;
/**
* Constructs a new Grid that is attached to a detail RelationView.
* @param relView the detail view to attach the Grid
* @param masterView the master view
* @exception symjava.sql.SQLException Thrown when the Grid cannot
* be successfully setup due to a database problem
*/
public Grid(symantec.itools.db.pro.RelationView relView,
symantec.itools.db.pro.RelationView masterView,
int coltoshow)
throws symjava.sql.SQLException
{
name = relView.getName();
relation = relView;
master =masterView;
DbaDataStore store = new DbaDataStore(relView, masterView);
//if(coltos!=0)
store.setColtoShow(coltoshow);
dataSource = new DbDataSource(this, store, store, store);
dataSource.setDefaultData();
assignDefaults();
if (dataSource.supportsMeta()) {
try {
dataSource.setupGrid(this);
} catch(Exception e) {
e.printStackTrace();
}
}
rvmd = relView.getMetaData();
setupAutonumbering(1);
installDefaultEventHandler();
}
/**
* Constructs a Grid using the specified DataSource instance. If the
* DataSource supports meta data then it will be used to setup the Grid.
* @param ds The DataSource used to keep the Grid's data
*/
public Grid(DataSource ds) {
dataSource = ds;
dataSource.setDefaultData();
assignDefaults();
dataSource.setGrid(this);
if (dataSource.supportsMeta()) {
try { dataSource.setupGrid(this); } catch(Exception e) {
e.printStackTrace();
}
}
}
boolean guiConstructed = false;
void assignDefaults() {
initDefaults();
if (!guiConstructed) {
String osName = System.getProperty("os.name");
if (osName.regionMatches(true, 0, "Sol", 0, 3) ||
osName.regionMatches(true, 0, "Sun", 0, 3)) {
onSolaris = true;
button = new Button("Button Solaris");
add(button);
button.setBackground(Color.lightGray);
}
// redrawer.start();
setLayout(new BorderLayout());
setFont(CellHints.stdFont);
setBackground(Color.white);
setForeground(Color.black);
vsb = new Scrollbar(Scrollbar.VERTICAL);
vsb.hide();
toolbar = new Panel();
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
toolbar.setBackground(Color.lightGray);
hsb = new Scrollbar(Scrollbar.HORIZONTAL);
Canvas pad = new Canvas();
pad.resize(vsb.preferredSize().width, hsb.preferredSize().height);
bottomPanel = new Panel();
bottomPanel.setBackground(Color.lightGray);
bottomPanel.setLayout(new BorderLayout());
bottomPanel.add("West", toolbar);
Panel padding = new Panel();
padding.setLayout(new BorderLayout());
padding.add("North", hsb);
bottomPanel.add("Center", padding);
bottomPanel.add("East", pad);
add("East",vsb);
add("South", bottomPanel);
guiConstructed = true;
}
hints = new CellHints(this);
defaultCell = new BasicCell(this, dataSource);
defaultCell.setCoordinates(new Coordinate(0, 0));
defaultCell.setDefaultFlag();
headingHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
cellHeight = headingHeight;
cells = new Matrix();
colHeadings = new Matrix();
cellAttributes = new Matrix(); //cell hints
headingAttributes = new Matrix(); //col heading hints
headingSource = new DefaultDataSource(this);
rowHeadingSource = new DefaultDataSource(this, true);
rowHeadingHints = new CellHints(this);
setCornerCell(defaultHeadingCell_);
setDefaultRowHeadingCell(defaultHeadingCell_);
try {
rowHeadingSource.setData(0, 1, new ImageStringData(dataSource, ""));
rowHeadingSource.setDefaultData(new ImageStringData(dataSource));
} catch(TypeNotSupported ex) {}
}
/**
* Sets the DataSource for keeping the Grid's data. Replaces the previous
* DataSource if previously set.
* @param ds The DataSource to keep the Grid's data.
*/
public /* synchronized */ void setDataSource(DataSource ds) {
clear();
dataSource = ds;
dataSource.setDefaultData();
assignDefaults();
dataSource.setGrid(this);
if (dataSource.supportsMeta()) {
try { dataSource.setupGrid(this); } catch(Exception e) {
e.printStackTrace();
}
}
}
/**
* Gets the DataSource for keeping the Grid's data.
*/
public DataSource getDataSource() {
return dataSource;
}
/**
* Sets the automatic redraw behavior of the Grid. If auto redraw is
* turned on then adding rows or changing data will cause the grid to
* automatically redraw. Turning it off can improve performance when
* making many changes at one time.
* @param redraw true to turn on automatic redrawing
*/
public void setAutoRedraw(boolean redraw) {
autoRedraw = redraw;
}
/**
* Gets the automatic redrawing setting.
*/
public boolean getAutoRedraw() {
return autoRedraw;
}
/**
* Installs the Grid's default event handler used to handle cell and
* table level events and perform actions required when exception occur.
*/
public void installDefaultEventHandler() {
installEventHandler(new DefaultTvEventHandler());
}
/**
* Installs an event handler used to handle cell and
* table level events and perform actions required when exception occur.
*/
public void installEventHandler(TvEventHandler h) {
eventHandler = h;
eventHandler.setupView(this);
}
/**
* Adds an add button to the Grid's toolbar.
*/
public void addAppendButton() {
addToolbarButton(appendRowLabel);
}
/**
* Adds an add button to the Grid's toolbar with the specified label.
*/
public void addAppendButton(String label) {
removeAppendButton();
appendRowLabel = label;
addToolbarButton(label);
}
/**
* Removes the add button from the toolbar.
*/
public void removeAppendButton() {
removeToolbarButton(appendRowLabel);
}
/**
* Adds an insert button to the Grid's toolbar.
*/
public void addInsertButton() {
addToolbarButton(insertRowLabel);
}
/**
* Adds an insert button to the Grid's toolbar.
*/
public void addInsertButton(String label) {
removeInsertButton();
insertRowLabel = label;
addToolbarButton(label);
}
/**
* Removes the insert button to the Grid's toolbar.
*/
public void removeInsertButton() {
removeToolbarButton(insertRowLabel);
}
/**
* Adds a delete button to the Grid's toolbar.
*/
public void addDeleteButton() {
addToolbarButton(deleteRowLabel);
}
/**
* Adds a delete button to the Grid's toolbar with the specified label.
*/
public void addDeleteButton(String label) {
removeDeleteButton();
deleteRowLabel = label;
addToolbarButton(label);
}
/**
* Removes the delete button to the Grid's toolbar.
*/
public void removeDeleteButton() {
removeToolbarButton(deleteRowLabel);
}
/**
* Adds a save button to the Grid's toolbar.
*/
public void addSaveButton() {
addToolbarButton(saveLabel);
}
/**
* Adds a save button to the Grid's toolbar with the specified label.
*/
public void addSaveButton(String label) {
removeSaveButton();
saveLabel = label;
addToolbarButton(label);
}
/**
* Removes the save button to the Grid's toolbar.
*/
public void removeSaveButton() {
removeToolbarButton(saveLabel);
}
/**
* Adds a restart button to the Grid's toolbar.
*/
public void addRestartButton() {
addToolbarButton(restartLabel);
}
/**
* Adds a restart button to the Grid's toolbar with the specified label.
*/
public void addRestartButton(String label) {
removeRestartButton();
restartLabel = label;
addToolbarButton(label);
}
/**
* Removes the restart button to the Grid's toolbar.
*/
public void removeRestartButton() {
removeToolbarButton(restartLabel);
}
/**
* Adds a delete button to the Grid's toolbar.
*/
public void addUndeleteButton() {
addToolbarButton(undeleteRowLabel);
}
/**
* Adds a delete button to the Grid's toolbar with the specified label.
*/
public void addUndeleteButton(String label) {
removeUndeleteButton();
undeleteRowLabel = label;
addToolbarButton(label);
}
/**
* Removes the delete button to the Grid's toolbar.
*/
public void removeUndeleteButton() {
removeToolbarButton(undeleteRowLabel);
}
/**
* Removes the undo button to the Grid's toolbar.
*/
public void addUndoButton() {
addToolbarButton(undoRowLabel);
}
/**
* Adds a undo button to the Grid's toolbar with the specified label.
*/
public void addUndoButton(String label) {
removeUndoButton();
undoRowLabel = label;
addToolbarButton(label);
}
/**
* Removes the undo button to the Grid's toolbar.
*/
public void removeUndoButton() {
removeToolbarButton(undoRowLabel);
}
Panel gotoPanel;
java.awt.TextField gotoTextField;
Button gotoButton;
/**
* Add a goto button to the Grid's toolbar.
*/
public void addGotoButton() {
if (gotoPanel == null) {
gotoPanel = new Panel();
gotoPanel.setLayout(new FlowLayout(FlowLayout.LEFT, 5, 0));
gotoPanel.add(gotoButton = new Button(gotoRowLabel));
gotoPanel.add(gotoTextField = new java.awt.TextField(4));
} else {
return;
}
addToToolbar(gotoPanel);
}
/**
* Removes the goto button to the Grid's toolbar.
*/
public void removeGotoButton() {
if (gotoPanel == null) {
return;
} else {
removeFromToolbar(gotoPanel);
gotoPanel = null;
}
}
/**
* Adds a button to the Grid's toolbar using the specified label.
*/
public void addToolbarButton(String label) {
Enumeration e = toolbarComponents.elements();
Component c;
while(e.hasMoreElements()) {
c = (Component)e.nextElement();
if (c instanceof Button && ((Button)c).getLabel().equals(label)) {
return;
}
}
addToToolbar(new Button(label));
}
/**
* Removes a button to the Grid's toolbar using the specified label.
*/
public void removeToolbarButton(String label) {
Enumeration e = toolbarComponents.elements();
Component c;
while(e.hasMoreElements()) {
c = (Component)e.nextElement();
if (c instanceof Button && ((Button)c).getLabel().equals(label)) {
toolbarComponents.removeElement(c);
return;
}
}
}
/**
* Returns whether the specified component is located on the toolbar
* @param c The component to check the toolbar for containment
*/
public boolean isToolbarComponent(Object c) {
return toolbarComponents.contains(c) || c == gotoTextField || c == gotoButton;
}
/**
* Adds a component to the toolbar
* @param c The component to add
*/
public void addToToolbar(Component c) {
toolbarComponents.addElement(c);
toolbar.add(c);
}
/**
* Removes an item from the toolbar
*/
public void removeFromToolbar(Component c) {
toolbarComponents.removeElement(c);
toolbar.remove(c);
}
/**
* Sets whether the last column should be filled to the end of the visible
* space of the grid
*/
public void setFillLastColumn(boolean fill) {
fillLastColumn = fill;
}
/**
* Gets whether the last column should be filled to the end of the visible
* space of the grid
*/
public boolean getFillLastColumn() {
return fillLastColumn;
}
/**
* Set heading text and width. Only button styles are supported.
* @param h string for heading text
* @param col number of column (one relative)
* @param chars width of column in characters
*/
public void setHeading(String h, int col, int chars) {
ButtonCell cell = new ButtonCell(1, col);
cell.type(TableCell.COL_HEADING);
cell.setGrid(this, headingSource);
colHeadings.updateElement(0, col-1, cell);
try {
headingSource.setData(cell.getCoordinates(),
new ImageStringData(dataSource, h));
} catch(TypeNotSupported ex) {}
setHeadingSize(col, chars);
if (autoRedraw) {
redrawAsync();
}
}
/**
* Set column width of a column.
* @param col column number to set width
* @param chars width of column in characters
*/
public /* synchronized */ void setHeadingSize(int col, int chars) {
CellHints hints = getHeadingHints(0, col);
int width = getFontMetrics(hints.font).charWidth('W') * chars;
resizeColumn(col, splitters[col-1] + width);
}
/**
* Sets the preferred row count. Used to determine the preferred size
*/
public void setPreferredRowCount(int c) { preferredRowCount = c; }
/**
* Gets the preferred row count. Used to determine the preferred size
*/
public int getPreferredRowCount() { return preferredRowCount; }
/**
* Returns the preferred size of this component.
* @see #minimumSize
*/
public Dimension preferredSize() {
int w=0, h=0;
w = splitters[splitters.length-1] + rowHeadingWidth;
h = (preferredRowCount + 1) * cellHeight;
Dimension toolsize = toolbar.size();
return new Dimension(Math.max(w, toolsize.width),
h + toolsize.height);
}
/**
* Returns the minimum size of this component.
* @see #preferredSize
* @see LayoutManager
*/
public Dimension minimumSize() {
return preferredSize();
}
/**
* Create specified number of columns for Grid.
* @param i number of columns for MulitList
*/
public /* synchronized */ void createColumns(int i) {
dataSource.clear();
//set the corner cell hints
headingAttributes.addElement(0, 0, new CellHints(this));
//set cell and heading hints
for(int col=1;col<=i;col++) {
cellAttributes.addElement(0, col, new CellHints(this));
headingAttributes.addElement(0, col, new CellHints(this));
}
splitters = new int[i+1];
}
//-----------------------------------------------------------------------------
// Heading APIs
//-----------------------------------------------------------------------------
/**
* Sets the cell to be used by the corner cell. The corner cell is in
* the upper left and is only visible if row headings are present.
*/
public /* synchronized */ void setCornerCell(TableCell c) {
cornerCell = c.cloneCell();
cornerCell.setGrid(this, rowHeadingSource);
cornerCell.setCoordinates(new Coordinate(0, 1));
cornerCell.type(TableCell.CORNER_CELL);
}
/**
* Sets the cell type used to display the row headings. All row headings
* must be of the same type.
*/
public /* synchronized */ void setDefaultRowHeadingCell(TableCell c) {
headingCell = c.cloneCell();
headingCell.setGrid(this, rowHeadingSource);
}
/**
* Sets the width of the row headings
*/
public /* synchronized */ void setRowHeadingWidth(int w) {
rowHeadingWidth = w;
}
/**
* Gets the width of the row headings
*/
public /* synchronized */ int getRowHeadingWidth(int w) {
return rowHeadingWidth;
}
/**
* Sets whether row headings should be displayed.
*/
public void useRowHeadings(boolean use) {
rowHeadingHints.visible = use;
}
/**
* Gets whether row headings should be displayed.
*/
public boolean isUsingRowHeadings() {
return rowHeadingHints.visible;
}
/**
* Sets the display height of cells.
*/
public /* synchronized */ void setCellHeight(int h) {
int stdHeight = getFontMetrics(CellHints.stdFont).getHeight() + 4;
if (h < stdHeight) {
cellHeight = stdHeight;
} else {
cellHeight = h;
}
if (autoRedraw) {
redrawAsync();
}
}
/**
* Sets the row heading style.
* @param s The style and must be one of BLANK or AUTONUMBER
*/
public /* synchronized */ void setRowLabelHeadingStyle(int s) {
if (s < AUTONUMBER || s > USER_DEFINED) {
throw new IllegalArgumentException("Illegal heading label style");
}
rowHeadingLabelStyle = s;
if (s == AUTONUMBER) {
rowHeadingSource.doAutoNumbering(true);
} else {
rowHeadingSource.doAutoNumbering(false);
}
}
/**
* Gets the number of the first row in the Grid
*/
public int getFirstAutoNumber() {
return rowHeadingWidth;
}
/**
* Causes row headings to be visible displaying row numbers starting with
* the specified value.
* @param first The number of the first row
*/
public void setupAutonumbering(int first) {
setupAutonumbering(first, rowHeadingWidth);
}
/**
* Causes row headings to be visible displaying row numbers starting with
* the specified value and sets the row headings to a fixed width to start.
* @param first The number of the first row
* @param pixels The starting width of the row headings
*/
public /* synchronized */ void setupAutonumbering(int first, int pixels) {
rowHeadingLabelStyle = AUTONUMBER;
rowHeadingSource.doAutoNumbering(true, first);
rowHeadingHints.visible = true;
rowHeadingWidth = pixels;
}
/**
* Sets the default value used when the row headings do not contain
* data for the row
*/
public /* synchronized */ void setDefaultRowData(String s) {
rowHeadingSource.setDefaultData(new ImageStringData(dataSource, s));
}
/**
* Sets the default data used when the row headings do not contain
* data for the row
*/
public /* synchronized */ void setDefaultRowData(Data d) {
rowHeadingSource.setDefaultData(d);
}
/**
* Sets the row heading label alignment style.
* @param a The alignment style: LEFT, CENTER, RIGHT
*/
public /* synchronized */ void setRowHeadingAlignment(int a) {
if (a < LEFT || a > RIGHT) {
throw new IllegalArgumentException("Illegal alignment style");
}
rowHeadingHints.align = a;
}
/**
* Gets the row heading label style
* @return The alignment style: LEFT, CENTER, RIGHT
*/
public int getRowLabelHeadingStyle() {
return rowHeadingLabelStyle;
}
/**
* Gets the row heading alignment style
* @return The alignment style: LEFT, CENTER, RIGHT
*/
public int getRowHeadingAlignment() {
return rowHeadingHints.align;
}
/**
* Gets column heading text of specified column.
*/
public String getHeading(int col) {
return cells.elementAt(-1, col).toString();
}
/**
* Set the font of the column heading text.
* @param f font instance for heading text.
* @param col the heading column to set (1 relative).
*/
public /* synchronized */ void setHeadingFont(Font f, int col) {
CellHints hints = getHeadingHints(0, col);
hints.font = f;
headingHeight = getFontMetrics(f).getHeight();
if (autoRedraw) { redrawAsync(); }
}
/**
* Returns the font of the column heading text
* @param col the heading column to get (1 relative).
*/
public Font getHeadingFont(int col) {
return getHeadingHints(0, col).font();
}
//-----------------------------------------------------------------------------
// Cell Control APIs
//-----------------------------------------------------------------------------
/**
* Gets the cell that currently possesses the keyboard focus.<p>
* WARNING: This is shared data - Do not hold onto this past current call!!
* @return The TableCell that has the keyboard focus.
*/
public TableCell getCurrentCell() {
return currSelectedCell;
}
/**
* Gets the data for the cell that currently has the keyboard focus.<p>
* WARNING: This is shared data - Do not hold onto this past current call!!
* @return The Data instance for the cell that has the keyboard focus.
* @exception DataNotAvailable If the DataSource does not currently have
* data for the cell
*/
public Data getCurrentCellData() throws DataNotAvailable {
if (currSelectedCell == null) return null;
return dataSource.getData(currSelectedCell.getCoordinates());
}
/**
* Gets the coordinate of the cell that has the keyboard focus
*/
public Coordinate getCurrentCellCoordinates() {
if (currSelectedCell == null) return null;
Coordinate c = currSelectedCell.getCoordinates();
//make one relative
return new Coordinate(c.row()+1, c.col()+1);
}
/**
* Ensures that no cell is marked as the current cell for editing
*/
public /* synchronized */ void clearCurrentCell() {
if (currSelectedCell == null) {
return;
}
sendFocusEvents(currSelectedCell, null);
}
/**
* Sets the cell that has the keyboard focus to the one at the specified
* row and column
*/
public /* synchronized */ void setCurrentCell(int row, int col) {
row--;
col--;
TableCell newSelection = null;
if (currSelectedCell == null || row != currSelectedCell.row() ||
col != currSelectedCell.col())
{
if (!cells.contains(row, col)) {
if (row < 0 || !validRow(row)
|| col < 0 || col >= getNumberOfCols())
{
//row and/or column not valid
return;
}
//then we need to use the default cell
newSelection = getUniqueCell(row, col);
} else {
newSelection = (TableCell)cells.elementAt(row, col);
}
sendFocusEvents(currSelectedCell, newSelection);
}
}
/**
* Sets the background color for a column
*/
public /* synchronized */ void setColBgColor(int col, Color bg) {
CellHints h = getColHints(col-1);
h.bg = bg;
}
/**
* Sts the background color for a row
*/
public /* synchronized */ void setRowBgColor(int row, Color bg) {
row--;
CellHints h = getRowHints(row);
if (h == null) {
h = new CellHints(this);
addRowHint(row, h);
}
h.set(CellHints.BG_BIT);
h.bg = bg;
}
/**
* Sets the background color for a cell
*/
public /* synchronized */ void setCellBgColor(int row, int col, Color bg) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h == null) {
h = new CellHints(this);
addCellHint(row, col, h);
}
h.set(CellHints.BG_BIT);
h.bg = bg;
}
/**
* Sets the foreground color for a column
*/
public /* synchronized */ void setColFgColor(int col, Color fg) {
CellHints h = getColHints(col-1);
h.fg = fg;
}
/**
* Sets the foreground color for a row
*/
public /* synchronized */ void setRowFgColor(int row, Color fg) {
row--;
CellHints h = getRowHints(row);
if (h == null) {
h = new CellHints(this);
addRowHint(row, h);
}
h.set(CellHints.FG_BIT);
h.fg = fg;
}
/**
* Sets the foreground color for a cell
*/
public /* synchronized */ void setCellFgColor(int row, int col, Color fg) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h == null) {
h = new CellHints(this);
addCellHint(row, col, h);
}
h.set(CellHints.FG_BIT);
h.fg = fg;
}
/**
* Set the font of for a column.
* @param col the column to set the font
* @param f font instance for cell text
*/
public /* synchronized */ void setColFont(int col, Font f) {
CellHints h = getColHints(col);
h.font = f;
cellHeight = getFontMetrics(f).getHeight() + 4;
if (autoRedraw) { redrawAsync(); }
}
/**
* Set the font of for a row.
* @param row the row to set the font
* @param f font instance for cell text
*/
public /* synchronized */ void setRowFont(int row, Font f) {
row--;
CellHints h = getRowHints(row);
if (h == null) {
h = new CellHints(this);
addRowHint(row, h);
}
h.set(CellHints.FONT_BIT);
h.font = f;
}
/**
* Set the font of for a cell.
*/
public /* synchronized */ void setCellFont(int row, int col, Font f) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h == null) {
h = new CellHints(this);
addCellHint(row, col, h);
}
h.set(CellHints.FONT_BIT);
h.font = f;
}
/**
* Returns the current font setting for cell text.
*/
public Font getColFont(int col) {
col--;
return getColHints(col).font();
}
/**
* Sets whether the cells in a column may be edited
*/
public /* synchronized */ void setColEditable(int col, boolean edit) {
// align must be LEFT, CENTER, or RIGHT
CellHints h = getColHints(col-1);
h.editable = edit;
}
/**
* Sets whether the cells in a row may be edited
*/
public /* synchronized */ void setRowEditable(int row, boolean edit) {
row--;
CellHints h = getRowHints(row);
if (h == null) {
h = new CellHints(this);
addRowHint(row, h);
}
h.set(CellHints.EDITABLE_BIT);
h.editable = edit;
}
/**
* Sets whether a cell can be edited
*/
public /* synchronized */ void setCellEditable(int row, int col, boolean edit) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h == null) {
h = new CellHints(this);
addCellHint(row, col, h);
}
h.set(CellHints.EDITABLE_BIT);
h.editable = edit;
}
/**
* Clears the CellHints for a cell
*/
public /* synchronized */ void clearCellHint(int row, int col, int bit) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h != null) {
h.clear(bit);
}
}
/**
* Clears the CellHints for a row
*/
public /* synchronized */ void clearRowHint(int row, int bit) {
row--;
CellHints h = getRowHints(row);
if (h != null) {
h.clear(bit);
}
}
/**
* Gets whether CellHints a set for a particular cell.
* @param row The cell row
* @param col The cell column
* @param bit The particular variable of the hint that is of interest as
* defined in CellHints
*/
public boolean isCellHintSet(int row, int col, int bit) {
row--; col--;
CellHints h = getCellHints(row, col);
if (h != null) {
return h.get(bit);
}
return false;
}
/**
* Gets whether CellHints a set for a particular row.
* @param row The cell row
* @param bit The particular variable of the hint that is of interest as
* defined in CellHints
*/
public boolean isRowHintSet(int row, int bit) {
row--;
CellHints h = getRowHints(row);
if (h != null) {
return h.get(bit);
}
return false;
}
/**
* Gets whether CellHints a set for a particular column.
* @param col The cell column
* @param bit The particular variable of the hint that is of interest as
* defined in CellHints
*/
public boolean getColEditable(int col) {
col--;
return getColHints(col).editable();
}
/**
* Sets whether the column heading of interest is editable.
*/
public /* synchronized */ void setHeadingEditable(int col, boolean edit) {
CellHints h = getHeadingHints(0, col);
h.editable = edit;
}
/**
* Gets whether the column heading of interest is editable.
*/
public boolean getHeadingEditable(int col) {
return getHeadingHints(0, col).editable();
}
/**
* Set the heading foreground and background colors of the heading hints
* @fg foreground Color for heading text
* @bg background Color for heading text
*/
public /* synchronized */ void setHeadingColors(int col, Color fg, Color bg) {
CellHints h = getHeadingHints(0, col);
h.fg = fg;
h.bg = bg;
if (autoRedraw) { redrawAsync(); }
}
/**
* Returns the color of the column heading foreground.
*/
public Color getHeadingFg(int col) {
CellHints h = getHeadingHints(0, col);
return h.fg;
}
/**
* Returns the color of the column heading background.
*/
public Color getHeadingBg(int col) {
CellHints h = getHeadingHints(0, col);
return h.bg;
}
/**
* Get the column size in pixels for the specified column.
* @param i number of column (one relative)
*/
public int getColumnSize(int i) {
return getColumnWidth(i-1);
}
/**
* Set the justification of the text for the specified column.
* @param i number of column (one relative)
* @param align one of the values LEFT, CENTER, or RIGHT
*/
public /* synchronized */ void setColumnAlignment(int col, int align) {
// align must be LEFT, CENTER, or RIGHT
CellHints h = getColHints(col-1);
h.align = align;
h = getHeadingHints(0, col);
h.align = align;
}
/**
* Returns the current number of rows.
*/
public int getNumberOfRows() {
try {
dataSource.fetchMode(true);
return Math.max(cells.rows(), dataSource.fetchAllRows());
} finally {
dataSource.fetchMode(false);
}
}
/**
* Returns the current number of columns.
*/
public int getNumberOfCols() {
return splitters.length - 1;
}
/**
* Ensures the topRow variable is valid
*/
public void setTopRow() {
setTopRow(-1);
}
/**
* Sets the top row to be displayed when table is drawn.
*/
public /* synchronized */ void setTopRow(int row) {
//visible from outside so row is one relative
if (row >= 1) {
topRow = row-1;
}
try {
int dataRows = dataSource.validDataRowRange(0, topRow+1);
//using top row resulted in a valid range so we're done
return;
} catch(DataNotAvailable exc) {
//no data so all up to cells
if (topRow <= cells.rows()-1) {
//there are enough cells so everything is OK
return;
}
//Need to reset topRow to valid number so how about 0
topRow = 0;
}
}
/**
* Gets the top row that is used when the Grid is drawn.<p>
* WARNING: The value returned is 0 relative
* @return The top row - 0 relative
*/
public int getTopRow() {
return topRow;
}
/**
* Gets the actual number of rows being painted.
*/
public int getNumberOfVisibleRows() {
setTopRow();
int count = (int)((height-3)/cellHeight) - 1;
try {
int dataRows = dataSource.validDataRowRange(topRow, topRow+count);
int lastCellRow = cells.rows();
count = Math.min(count, Math.max(dataRows, lastCellRow)-topRow+1);
} catch(DataNotAvailable exc) {
//no data so all up to cells
if (count > cells.rows()) {
count = cells.rows()-topRow;
}
}
// System.out.println("getNumberOfVisibleRows " + String.valueOf(count));
return count;
}
/**
* Sets the mouse capture to the currently selected cell.
*/
public void setCapture() {
if (rowHeadingCell(currCaptureCell) && currSelectedCell != currCaptureCell) {
currHeadingCell = null;
}
currCaptureCell = currSelectedCell;
}
/**
* Set mouse capture to a particular cell
*/
public void setCapture(TableCell c) {
if (rowHeadingCell(currCaptureCell) && c != currCaptureCell) {
currHeadingCell = null;
}
currCaptureCell = c;
}
/**
* Removes the mouse capture if a cell currently possess it.
*/
public void lostCapture() {
if (rowHeadingCell(currCaptureCell)) {
currHeadingCell = null;
}
currCaptureCell = null;
}
/**
* Gets whether a cell currently has mouse capture.
*/
public boolean cellHasCapture() {
return currCaptureCell != null;
}
/**
* Remove all rows from the Grid.
*/
public /* synchronized */ void clear() {
clearAllSelections();
cells.removeAllElements();
if (dataSource != null) {
dataSource.clear();
}
xDragLast = -1;
isDragging = false;
topRow = 0;
leftCol = 1;
vsb.setValue(0);
hsb.setValue(0);
currSelectedCell = currCaptureCell = null;
if (autoRedraw) { redrawAsync(); }
}
/**
* Adds a cell to the Grid
* @param cell The cell to be displayed
* @param s The value for the cell
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public /* synchronized */ void addCell(TableCell cell, String s) throws TypeNotSupported {
cell = cell.cloneCell();
cell.setGrid(this, dataSource);
cells.updateElement(cell.row(), cell.col(), cell);
dataSource.setData(cell.getCoordinates(),
new ImageStringData(dataSource, s));
if (autoRedraw) { redrawAsync(); }
}
/**
* Adds or changes the text of a row and column position.
* @param r index of row
* @param c index of column
* @param s String text for cell
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public /* synchronized */ void addTextCell(int r, int c, String s) throws TypeNotSupported {
r--; c--;
dataSource.setData(r, c, new ImageStringData(dataSource, s));
if (autoRedraw) {
redrawAsync();
}
}
/**
* Adds or changes the image of a row and column position.
* @param r index of row
* @param c index of column
* @param i image instance for cell
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public /* synchronized */ void addImageCell(int r, int c, Image i) throws TypeNotSupported {
r--; c--;
dataSource.setData(r, c, new ImageStringData(dataSource, i));
if (autoRedraw) {
redrawAsync();
}
}
/**
* Add/change contents of a cell, both text and image.
* @param r index of row
* @param c index of column
* @parma s string text for cell
* @param i image instance for cell
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public /* synchronized */ void addCell(int r, int c, String s, Image i) throws TypeNotSupported {
r--; c--;
dataSource.setData(r, c, new ImageStringData(dataSource, s, i));
if (autoRedraw) {
redrawAsync();
}
}
/**
* Gets string text of specified cell.
* @param r index of row
* @param c index of column
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public String getCellText(int r, int c) throws DataNotAvailable {
r--; c--;
return dataSource.getData(r, c).toString();
}
/**
* Gets the data value for a specified cell
* @param r index of row
* @param c index of column
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public Data getCellData(int r, int c) throws DataNotAvailable {
r--; c--;
return dataSource.getData(r, c);
}
/**
* Gets the FontMetrics for the specified cell
*/
public FontMetrics getCellFontMetrics(TableCell c) {
Font f = getCellFont(c);
return getFontMetrics(f);
}
/**
* Inherited from Component.
*/
public void update(Graphics g) {
paint(g);
}
void checkClipping(Graphics g) {
Rectangle r = g.getClipRect();
Dimension d = size();
if (r.x != 0 || r.y != 0 ||
r.width != d.width ||
r.height != d.height) {
repaint();
}
}
/**
* Inherited from Component.
*/
public /* synchronized */ void paint(Graphics g) {
checkClipping(g);
if ((width!=(size().width)) || (height!=size().height)) {
redrawAsync();
}
if (im == null) { return; }
g.drawImage(im, 0, 0, this);
}
/**
* Inherited from Component.
*/
public void addNotify() {
super.addNotify();
repaint();
}
void showScrollbars() {
Dimension d = size(),
actualViewSize = new Dimension(),
reqdViewSize = new Dimension(),
hsbSize = bottomPanel.preferredSize(),
vsbSize = vsb.preferredSize();
boolean changed = false,
showVsb = false;
int reqdHeight = cells.rows();
try {
int dataRows = dataSource.validDataRowRange(0,getPageSize().height+2+topRow);
reqdHeight = Math.max(reqdHeight, dataSource.rows());
} catch(DataNotAvailable exc) {}
actualViewSize.height = height - headingHeight - 3 - bottomPanel.size().height;
actualViewSize.width = d.width;
reqdViewSize.height = reqdHeight * cellHeight;
reqdViewSize.width = splitters[splitters.length-1] + rowHeadingWidth;
//check to see if horizontal scrollbar will be shown
if (reqdViewSize.width > actualViewSize.width) {
//definitely reqd
actualViewSize.height -= hsbSize.height;
} else if (reqdViewSize.width > actualViewSize.width - vsbSize.width) {
//see if acutally need vertical scrollbar
if (reqdViewSize.height > actualViewSize.height - hsbSize.height) {
//should need veritcal vsb and thus hsb scrollbar
actualViewSize.height -= hsbSize.height;
}
}
//show vertical scrollbar if appropriate
if (reqdViewSize.height > actualViewSize.height) {
vsb.setValues(vsbPosition, getPageSize().height, 0, reqdHeight-1);
vsb.setPageIncrement(getPageSize().height);
vsb.show();
changed = showVsb = true;
actualViewSize.width -= vsbSize.width;
} else {
topRow = 0;
vsb.hide();
showVsb = false;
}
//show horizontal scrollbar if appropriate
if (reqdViewSize.width > actualViewSize.width) {
//determine what the last column completely visible is
int i = 1;
int row = 0, col = 0;
if (currSelectedCell != null) {
Coordinate c = currSelectedCell.getCoordinates();
row = c.row;
col = c.col;
}
int shiftLeft = splitters[leftCol - 1] + rowHeadingWidth;
for (;i<splitters.length; i++) {
if (splitters[i] - shiftLeft > actualViewSize.width) break;
}
if (vsb.isVisible()) {
actualViewSize.width -= vsb.size().width;
}
int sliderWidth = (int)((float)actualViewSize.width/reqdViewSize.width*getNumberOfCols());
hsb.setValues(hsbPosition,
sliderWidth,
1,
splitters.length-1);
hsb.setPageIncrement(sliderWidth);
hsb.show();
changed = true;
} else {
leftCol = 1;
hsb.hide();
}
if (changed) {
getParent().paintAll(getParent().getGraphics());
}
}
/**
* Inherited from Component.
*/
public void show() {
redrawAsync();
}
/**
* Gets the column width of the specified column.
*/
public int getColumnWidth(int col) {
if (fillLastColumn && col == getNumberOfCols()-1) {
return size().width - splitters[col] + 1;
} else {
return splitters[col+1] - splitters[col];
}
}
boolean rowHeadingCell(TableCell cell) {
return cell != null &&
(cell == headingCell || cell == currHeadingCell
|| cell.type() == TableCell.ROW_HEADING);
}
//returns zero relative column number for last column that is visible
private int lastVisibleCol() {
int width = size().width;
for (int i=leftCol; i<splitters.length; i++) {
if (splitters[i]-splitters[leftCol-1]>width) {
return Math.min(i, getNumberOfCols());
}
}
return getNumberOfCols();
}
/**
* Gets the bounding rectangle of a cell relative to the grid
*/
public Rectangle getCellBounds(TableCell cell) {
return getCellBounds(cell, null);
}
/**
* Gets the bounding rectangle of a cell relative to the grid
* @param cell The cell to fetch the bounds
* @param b The rectangle object to place bounds in
*/
public Rectangle getCellBounds(TableCell cell, Rectangle b) {
Coordinate p = cell.getCoordinates();
if (cell == cornerCell) {
return new Rectangle(0, 0, rowHeadingWidth+1, headingHeight+2);
} else if (rowHeadingCell(cell)) {
return getRowHeadingBounds(cell, b);
} else if (cell.type() == TableCell.COL_HEADING) {
return getHeadingCellBounds(p, b);
}
return getCellBounds(p, b);
}
private Rectangle getCellBounds(Coordinate c, Rectangle b) {
int shiftLeft = splitters[leftCol-1];
int row = c.row;
int col = c.col;
int w = getColumnWidth(col);
int left = splitters[col] - shiftLeft-1+rowHeadingWidth;
if (leftCol-1 == col) { left++; }
else { w++; }
if (b == null) {
b = new Rectangle();
}
if (w > width - rowHeadingWidth) {
w = width - rowHeadingWidth;
if (vsb.isVisible()) { w -= vsb.size().width; }
}
b.reshape(left,
(row-topRow)*cellHeight + headingHeight + 2,
w,
cellHeight+1);
return b;
}
/**
* Gets the bounds of the column heading cell at the specified coordinate
* @param coords The coordinates of the heading
* @param b The rectangle to place the bounds values
*/
public Rectangle getHeadingCellBounds(Coordinate coords, Rectangle b) {
int shiftLeft = splitters[leftCol-1];
int row = coords.row;
int col = coords.col;
int w = getColumnWidth(col);
int left = splitters[col]-shiftLeft-1+rowHeadingWidth;
if (col == 0) { left++; }
else { w++; }
if (b == null) {
b = new Rectangle();
}
if (w > width - rowHeadingWidth) {
w = width - rowHeadingWidth;
if (vsb.isVisible()) { w -= vsb.size().width; }
}
b.reshape(left, 0, w, headingHeight+2);
return b;
}
/**
* Gets the bounds of the row heading cell at the specified coordinate
* @param cell The row heading cell
* @param b The rectangle to place the bounds values
*/
public Rectangle getRowHeadingBounds(TableCell cell, Rectangle b) {
b = getCellBounds(cell.getCoordinates(), b);
b.x = 0;
b.width = rowHeadingWidth+1;
return b;
}
/**
* Redraws a particular cell only.<p>
* This function should only be called if selection has not changed since last
* redraw. This function is provided to more efficiently redraw individual
* cell updates
*/
public void redrawCell(TableCell c) {
redrawCell(c, true);
}
/**
* Redraws a particular cell only.<p>
* This function should only be called if selection has not changed since last
* redraw. This function is provided to more efficiently redraw individual
* cell updates
* @param c The cell to redraw
* @param makeVisible Specifies whether the cell should be scrolled
* to make visible before being drawn
*/
public /* synchronized */ void redrawCell(TableCell c, boolean makeVisible) {
try {
if (!fetchMode) { dataSource.fetchMode(true); }
if (c != cornerCell && c.type() != TableCell.COL_HEADING
&& makeVisible && isCellVisible(c.row()+1, c.col()+1))
{
//make sure cell is visible if not heading
makeCellVisible(c.row()+1, c.col()+1);
} else if (!isCellVisible(c.row()+1, c.col()+1)) {
return;
}
hints.setHints(c);
//clear rectangle
gg.setColor(getBackground());
Rectangle r = hints.bounds();
gg.fillRect(r.x, r.y, r.width-1, r.height-1);
gg.setColor(getForeground());
c.drawCell(gg, hints);
if (c == currSelectedCell && c.isCellTypeEditable()) {
frameCurrentCells();
}
} finally {
if (!fetchMode) { dataSource.fetchMode(false); }
}
repaint();
}
/**
* Redraws a particular cell only.<p>
* This function should only be called if selection has not changed since last
* redraw. This function is provided to more efficiently redraw individual
* cell updates. This function is internal so it is 0 relative.
* @param row The row of the cell to redraw
* @param col The column of the cell to redraw
* @param makeVisible Specifies whether the cell should be scrolled
* to make visible before being drawn
*/
protected /* synchronized */ void redrawCell(int row, int col, boolean makeVisible) {
if (!validRow(row)) {
//not asking to redraw a column heading
return;
} else if (col > -1 && !validCol(col)) {
//not asking to redraw a row heading
return;
} else if (col == -1 && validRow(row)) {
redrawRowHeadingCell(row);
return;
} else if (col == -1 && row == -1) {
//corner cell and we are not worried about it
return;
}
TableCell c = getUniqueCell(row, col);
redrawCell(c, makeVisible);
drawTableBoundary();
}
/**
* Redraws all the cells in a row.
*/
public /* synchronized */ void redrawRow(int row) {
row--;
if(!validRow(row)) {
return;
}
fetchMode = true;
dataSource.fetchMode(true);
try {
int cols = getNumberOfCols();
for (int col=0; col<cols; col++) {
redrawCell(row, col, false);
}
redrawRowHeadingCell(row);
} finally {
dataSource.fetchMode(false);
fetchMode = false;
}
if (autoRedraw) { redrawAsync(); }
}
/**
* Redraws the specified cell and all of the bordering cells
*/
public /* synchronized */ void redrawAroundCell(TableCell c) {
//draw on all adjoining cells too
int row = c.row()-1;
int col = c.col()-1;
try {
fetchMode = true;
dataSource.fetchMode(true);
for (int i=0; i<=2; i++) {
for (int j=0; j<=2; j++) {
if (col+j > getNumberOfCols()-1) {
continue;
}
//redraw col heading
if (row+i < topRow) {
if (col+j < leftCol-1) {
//redraw corner cell
redrawCornerCell();
}
redrawColHeadingCell(col+j);
} else {
//redraw regular cell
if (isCellVisible(row+i+1, col+j+1)) {
redrawCell(row + i, col + j, false);
}
}
}
}
} finally {
fetchMode = false;
dataSource.fetchMode(false);
}
}
/**
* Gets the visible bounds of the drawing space required for the cells in
* the Grid.
*/
public Rectangle getTableBounds(Rectangle r) {
Dimension d = size();
r.reshape(0, 0, d.width, d.height);
if (vsb.isVisible()) {
r.width -= vsb.size().width;
}
r.height -= bottomPanel.size().height;
r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
if (rowHeadingHints.visible) {
r.width += rowHeadingWidth;
}
int visRows = (r.height-2)/cellHeight;
if (visRows + topRow > dataSource.rows()) {
r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
}
return r;
}
/**
* Draws the outline around the cells
*/
protected void drawTableBoundary() {
Dimension d = size();
Rectangle r = new Rectangle(0, 0, d.width, d.height);
//draw boundary around table panel
if (vsb.isVisible()) {
r.width -= vsb.size().width;
}
r.height -= bottomPanel.size().height;
gg.setColor(Color.black);
gg.drawRect(r.x, r.y, r.width-1, r.height-1);
//draw boundary around table
r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
if (rowHeadingHints.visible) {
r.width += rowHeadingWidth;
}
int visRows = (r.height-2)/cellHeight;
if (visRows + topRow > dataSource.rows()) {
r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
}
gg.drawRect(r.x, r.y, r.width-1, r.height-1);
}
/**
* Gets the bounds for the visible cells.
*/
protected Rectangle getVisibleCellBoundary() {
Dimension d = size();
Rectangle r = new Rectangle(0, 0, d.width, d.height);
//get height of table panel
r.height -= bottomPanel.size().height;
//get boundary around table
r.width = splitters[splitters.length-1] - splitters[leftCol-1] + 1;
if (rowHeadingHints.visible) {
r.width += rowHeadingWidth;
}
int visRows = (r.height-2)/cellHeight;
if (visRows + topRow > dataSource.rows()) {
r.height = headingHeight+2 + cellHeight*(dataSource.rows() - topRow)+2;
}
return r;
}
/**
* Inserts a new row above the specified row number
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public /* synchronized */ void insertRow(int beforeRow) throws TypeNotSupported {
Event e = new Event(this, INSERT, null);
beforeRow--;
e.y = beforeRow;
if (!dataSource.handleEvent(e)) {
dataSource.insertRow(beforeRow);
}
/*
if (currSelectedCell != null &&
currSelectedCell.row() >= beforeRow)
{
currSelectedCell.setRow(currSelectedCell.row()+1);
}
if (autoRedraw) { redrawAsync(); }
*/
}
/**
* Gets the state of the data in the specified row
* @return One of NEW_ROW, CLEAN_ROW, DELETED_ROW, MODIFIED_ROW as defined in
* DataSource
*/
public int rowState(int row) {
row--;
return dataSource.rowState(row);
}
/**
* Mark the specified row as not deleted
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public void undeleteRow(int row) throws TypeNotSupported {
undoCurrentCell(); // Just to make sure we can redraw it
setFocusToRow(row);
row--;
Event e = new Event(this, UNDELETE, null);
e.y = row;
if (!dataSource.handleEvent(e)) {
dataSource.undeleteRow(row);
row++;
//setFocusToRow(row);
}
}
/**
* Mark the specified row as deleted
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public void deleteRow(int row) throws TypeNotSupported {
undoCurrentCell(); // Just to make sure we can redraw it
setFocusToRow(row);
row--;
Event e = new Event(this, DELETE, null);
e.y = row;
if (!dataSource.handleEvent(e)) {
dataSource.deleteRow(row);
}
row++;
// Trial 0
//clearCurrentCell();
// setFocusToRow(row);
// Trial 1
//setFocusToRow(row);
// Trial 2
// redrawRow(row);
// sendFocusEvents(null, currSelectedCell);
// Trial 3
//redrawRowHeadingCell(row);
//repaint();
// if (autoRedraw) { redrawAsync(); }
}
/**
* Appends a new row to the end of the Grid
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public int appendRow() throws TypeNotSupported {
Event e = new Event(this, APPEND, null);
int newRow;
if (!dataSource.handleEvent(e)) {
newRow = dataSource.appendRow();
} else {
newRow = e.y;
}
if (autoRedraw) { redrawAsync(); }
return newRow;
}
/**
* Creates a new cell and adds it to the Matrix used to store TableCells.
* @param cell The default cell to clone to make the new cell.
*/
public void addCellFromDefault(TableCell cell) {
TableCell c = cell.cloneCell();
cells.addElement(c.row(), c.col(), c);
if (currSelectedCell == cell) { currSelectedCell = c; }
if (currCaptureCell == cell) { currCaptureCell = c; }
}
/**
* Gets the default cell and sets the coordinates to the specified values
*/
protected TableCell getDefaultCell(int row, int col) {
TableCell cell = defaultCell;
Coordinate c = cell.getCoordinates();
cell.reset();
c.row = row;
c.col = col;
return cell;
}
/**
* Gets the cell at the specified coordinats. If the cell does not exist in
* the cells Matrix, then the default cell is returned.
*/
protected TableCell getCell(int row, int col) {
if (currSelectedCell != null
&& currSelectedCell.row() == row && currSelectedCell.col() == col)
{
return currSelectedCell;
} else if (cells.contains(row, col)) {
return (TableCell)cells.elementAt(row, col);
} else {
return getDefaultCell(row, col);
}
}
/**
* Requests the DataSource to save the current state of the Grid
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public void save() throws TypeNotSupported {
dataSource.commitData();
dataSource.save();
redrawAsync();
/*
if (currSelectedCell != null) {
try {
dataSource.validDataRowRange(currSelectedCell.row(),
currSelectedCell.row());
} catch(DataNotAvailable ex) {
currSelectedCell = null;
currCaptureCell = null;
return;
}
dataSource.setCurrentRow(currSelectedCell.row());
}
*/
}
/**
* Requests the DataSource to refresh its data. Same as refresh but for
* backward compatibility.
*/
public void restart() {
refresh();
}
/**
* Requests the DataSource to refresh its data.
*/
public void refresh() {
dataSource.refresh();
/*
currSelectedCell = null;
currCaptureCell = null;
redrawAsync();
*/
}
/**
* Redraws the grid's offscreen image. Call when through making changes to grid.
* @param repaint If true, grid will be repainte after it is redrawn
* offscreen.
*/
public void redraw(boolean repaint) {
redraw();
if (repaint) {
repaint();
}
}
/**
* Redraws the Grid. Call when through making changes to Grid. Does not
* force a redraw of the offscreen image.
*/
public void redraw() {
Dimension d = size();
if (width != d.width || height != d.height) {
im = createImage(width = d.width,
height = d.height);
if (im == null) return;
gg = im.getGraphics();
}
forceRedraw(false);
}
/**
* Forces the offscreen image to be redraw. It does not check for a size
* change since the last redraw.
*/
public void forceRedraw(boolean repaint) {
// /* synchronized */(dataSource.getSynchronizationObject())
{
// System.out.println("**** Drawing rows for " + name);
if (gg == null)
{
// System.out.println("Nothing to draw for " + name);
return;
}
gg.setColor(getBackground());
gg.fillRect(0,0,width,height);
int count = 0;
try {
fetchMode = true;
dataSource.fetchMode(true);
setTopRow();
showScrollbars();
count = getNumberOfVisibleRows();
drawHeadings(count);
drawRows(count, topRow);
drawTableBoundary();
} finally {
fetchMode = false;
dataSource.fetchMode(false);
}
// System.out.println("@@@ Done drawing rows for " + name);
if (repaint) repaint();
}
}
public String name;
void drawRows(int count, int cellRow) {
int r = 0;
MatrixEnumeration e = cells.elements();
TableCell c = null;
int x, w;
int cols = getNumberOfCols();
int hx=0, hy=0, hw=0, hh=0;
int shiftLeft = splitters[leftCol-1];
int currRow=-1, currCol=-1;
if (cellRow > 0) {
if (cellRow >= cells.rows()) {
e = null;
} else {
c = (TableCell)e.advanceTo(cellRow);
}
}
int lastVisCol = lastVisibleCol();
//iterate the rows and paint each one
while(count-- > 0) {
//iterate the cols of the current row
for (int col=leftCol-1; col<cols && col<=lastVisCol; col++) {
w = getColumnWidth(col);
while (e != null
&& (c == null || (e.currCol() < col && e.currRow() <= cellRow))
&& e.hasMoreElements())
{
c = (TableCell)e.nextElement();
currRow = e.currRow();
currCol = e.currCol();
if (currRow <= cellRow && currCol < col) {
//keep going till get to correct column
c = null;
}
}
if (currRow == cellRow && currCol == col) {
hints.setHints(c);
c.drawCell(gg, hints);
c = null;
} else
if (currSelectedCell != null &&
//it is default cell, but could be currSelectedCell
currSelectedCell.row() == cellRow &&
currSelectedCell.col() == col)
{
hints.setHints(currSelectedCell);
currSelectedCell.drawCell(gg, hints);
} else {
//looks like this cell not set yet so use default
TableCell defCell = getDefaultCell(cellRow, col);
hints.setHints(defCell);
defCell.drawCell(gg, hints);
}
}
cellRow++;
r++;
}
if (currSelectedCell != null && currSelectedCell.isCellTypeEditable()) {
frameCurrentCells();
}
}
boolean drawFrame = true;
/**
* Sets whether current cell should have a frame drawn around it
*/
public boolean drawFrame() { return drawFrame; }
/**
* Gets whether current cell should have a frame drawn around it
*/
public boolean drawFrame(boolean draw) {
drawFrame = draw;
if (autoRedraw) {
redrawAsync();
}
return draw;
}
void frameCurrentCells() {
if (drawFrame && currSelectedCell != null) {
Rectangle r = getCellBounds(currSelectedCell);
if (r.x < rowHeadingWidth || r.y < headingHeight+2) { return; }
gg.setColor(Color.black);
gg.drawRect(r.x-1,r.y-1,r.width+1,r.height+1); //draw outside
gg.drawRect(r.x+1,r.y+1,r.width-3,r.height-3); //draw inside
}
}
int[] getColStartPositions() {
return splitters;
}
/**
* If the event handler is set, the exception is passed to the event handler.<p>
* This function is 0 relative!!
*/
public void handleException(int row, int col, Exception ex) {
try {
if (eventHandler != null) {
eventHandler.handleException(new Coordinate(row, col), ex);
}
}
catch (Exception e)
{
}
}
/**
* Requests the DataSource to undo some action to the specified row
* @exception TypeNotSupported If action is not supported by the DataSource
*/
public void undoRow(int row) throws TypeNotSupported {
undoCurrentCell();
if (rowState(row) == DataSource.MODIFIED_ROW)
{
row--;
dataSource.undoRow(row);
row++;
setFocusToRow(row);
}
}
/**
* Requests the DataSource to undo any changes made to the current cell
* since the last commit.
*/
public /* synchronized */ void undoCurrentCell() {
dataSource.rollbackCurrentData();
if (currSelectedCell != null) {
redrawCell(currSelectedCell);
}
}
/**
* Generates a Grid event and routes it through the grid for handling.
* It is forwarded to the DataSource and the event handler. If not
* handled by either, then it is forwarded through postEvent.
* CAUTION - CAUTION - CAUTION - CAUTION - CAUTION - CAUTION - CAUTION
*
* This method should only be called with Grid events!!!!!
*
* NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC - NOITUAC
*/
public /* synchronized */ boolean generateEvent(Event e, int id, TableCell cell) {
//save old info so can restore
Object oldTarget = e.target;
int oldId = e.id;
Object oldArg = e.arg;
boolean handled = false;
//update the event
e.id = id;
e.target = this;
e.arg = cell;
//always let the event go to the DataSource
handled = dispatchCellEvent(e);
//send the event to the datasource, if not handled there then send it up
if (!dataSource.handleEvent(e)) {
handled |= postEvent(e);
}
//restore event object
e.target = oldTarget;
e.id = oldId;
e.arg = oldArg;
return handled;
}
boolean dispatchCellEvent(Event e) {
if (eventHandler != null && e.arg instanceof TableCell) {
TableCell cell = (TableCell)e.arg;
if (rowHeadingCell(cell)) {
return eventHandler.handleRowHeadingEvent(e, cell);
} else if (cell.type() == TableCell.COL_HEADING) {
return eventHandler.handleColHeadingEvent(e, cell);
} else if (cell == cornerCell) {
return eventHandler.handleCornerCellEvent(e, cell);
} else {
//must be a cell
return eventHandler.handleCellEvent(e, cell);
}
}
return false;
}
boolean handleHeadingClick(Event e, int x, int y) {
int colstart[] = getColStartPositions();
int shiftLeft = colstart[leftCol-1] - rowHeadingWidth;
if (x <= rowHeadingWidth && rowHeadingHints.visible) {
//it was a click in row header region
if ((x < rowHeadingWidth + clickMargin) &&
(x > rowHeadingWidth - clickMargin)) {
dragColumn = 0;
isDragging = true;
mouseDrag(e, x, y); //draw drag line immediately
} else {
//upper left corner clicked
if (rowHeadingCell(currCaptureCell)) {
currHeadingCell = null;
}
currCaptureCell = cornerCell;
translate(e);
return cornerCell.mouseEvent(e);
}
return true;
} else {
// is it close enough to be a column size drag?
for (int i=leftCol-1; i<splitters.length; i++) {
if ((x < colstart[i] + clickMargin - shiftLeft) &&
(x > colstart[i] - clickMargin - shiftLeft)) {
dragColumn = i;
isDragging = true;
mouseDrag(e, x, y); //draw drag line immediately
return true;
}
}
}
//get the heading for the coordinates
TableCell cell = (TableCell)colHeadings.elementAt(0, columnClicked(x));
if (cell == null) {
return true;
}
if (rowHeadingCell(currCaptureCell)) {
currHeadingCell = null;
}
currCaptureCell = cell;
translate(e);
return cell.mouseEvent(e);
}
boolean handleRowHeadingClick(Event e, int x, int y) {
//return true;
//create a new current heading cell since this could be a shared resource
//during event handling
//get the heading for the coordinates
currHeadingCell = headingCell.cloneCell();
Coordinate c = currHeadingCell.getCoordinates();
c.row = cellRow(y);
c.col = 0;
if (!validRow(c.row)) return true;
currCaptureCell = currHeadingCell;
translate(e);
/* try{
dataSource.setCurrentRow(c.row);
} catch(TypeNotSupported ex) { handleException(c.row, c.col, ex); }*/
return currHeadingCell.mouseEvent(e);
}
boolean handleSuccessiveClick(Event e) {
//must only be called if no focus change
// track time elapsed since last mouseDown
long clickSpeed = e.when - clickTime;
TableCell cell = (currCaptureCell != null) ?currCaptureCell :currSelectedCell;
boolean handled;
if (cell == null) {
handled = false;
} else if (clickSpeed < CLICKTHRESHOLD) {
e.target = cell;
e.id = CELL_MOUSE_DOUBLE;
translate(e);
handled = cell.mouseEvent(e);
} else {
//single click so send mouse event to control
e.target = cell;
translate(e);
handled = cell.mouseEvent(e);
}
clickTime = e.when;
return handled;
}
int cellRow(int y) {
return ((int)(y-headingHeight-2)/cellHeight)+topRow;
}
int columnClicked(int x) {
int shiftLeft = splitters[leftCol - 1] - rowHeadingWidth;
for (int i=0; i<getNumberOfCols()-1; i++) {
if (x < splitters[i+1] - shiftLeft) {
return i;
}
}
if (x < rowHeadingWidth)
return -1; //header click
else
return getNumberOfCols()-1;
}
void setFocusToRow(int row)
{
row--;
if (currSelectedCell == null || currSelectedCell.row() != row)
{
row++;
gotoRow(row);
}
else
{
row++;
redrawRow(row);
sendFocusEvents(null, currSelectedCell);
}
}
void sendFocusEvents(TableCell lost, TableCell get) {
Event e = new Event(lost, Event.LOST_FOCUS, null);
int oldRow = -1;
if (currSelectedCell != null) {
oldRow = currSelectedCell.row();
}
if (lost != null) {
if (!lost.canLoseFocus()) {
//not a legal state so do not change
return;
}
//set selected cell to get so frame not drawn around cell
currSelectedCell = get;
lost.focusEvent(e);
lostCapture();
}
try{
if (oldRow != get.row())
{
dataSource.setCurrentRow(get.row());
}
} catch(TypeNotSupported ex) { handleException(get.row(), get.col(), ex); }
currSelectedCell = get;
e.target = get;
e.id = e.GOT_FOCUS;
get.focusEvent(e);
drawRowHeadings(getNumberOfVisibleRows());
//change currently selected row now
makeCellVisible(get.row()+1, get.col()+1);
clickTime = 0;
}
/**
* Inherited from Component
*/
public boolean mouseExit(Event e, int x, int y) {
frame().setCursor(Frame.DEFAULT_CURSOR);
return true;
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean mouseDown(Event e, int x, int y) {
buttonFocus();
if (e.target == vsb || e.target == hsb) {
//Netscape exposes mouseDown events for Scrollbars
return false;
}
Rectangle r = new Rectangle();
r = getTableBounds(r);
if (!r.inside(x, y)) {
return false;
}
// Check for a click on the heading area:
if (y<headingHeight+1) {
return handleHeadingClick(e, x, y);
} if (x < rowHeadingWidth && rowHeadingHints.visible) {
//click in row heading area
return handleRowHeadingClick(e, x, y);
}
//it's a click in the row area
//check for hit on the scrollbar
if (x > width) return true;
// set new row selection
int row = cellRow(y);
int col = columnClicked(x);
TableCell newSelection = null;
if (currSelectedCell == null || row != currSelectedCell.row() ||
col != currSelectedCell.col())
{
if (!cells.contains(row, col)) {
//check for mouse below last row
if (!validRow(row)) {
return true;
}
//then we need to use the default cell
newSelection = getDefaultCell(row, col).cloneCell();
newSelection.setDefaultFlag();
} else {
newSelection = (TableCell)cells.elementAt(row, col);
}
sendFocusEvents(currSelectedCell, newSelection);
if (cellHasCapture()) {
translate(e);
return currCaptureCell.mouseEvent(e);
}
} else {
//check for double click since didn't change cells
handleSuccessiveClick(e);
}
if (e.modifiers == Event.META_MASK) {
//right mouse click
}
return false;
}
/**
* Determines whether the specified row exists in the Grid. <p>
* This function is 0 based
*/
public boolean validRow(int row) {
if (row < 0) return false;
if (cells.rows()-1 > row) {
return true;
}
try {
dataSource.validDataRowRange(row, row);
} catch(DataNotAvailable exc) {
//Yep, it was a click below cells
return false;
}
return true;
}
/**
* Determines whether the specified column exists in the Grid. <p>
* This function is 0 based
*/
public boolean validCol(int col) {
return col >= 0 && col < getNumberOfCols();
}
/**
* Inherited from Component
*/
public boolean mouseDrag(Event e, int x, int y) {
if (isDragging) {
handleColDrag(x);
return true;
}
if (cellHasCapture()) {
translate(e);
return currCaptureCell.mouseEvent(e);
}
return false;
}
boolean captureByHeading() {
if (currCaptureCell == null) { return false; }
Coordinate c = currCaptureCell.getCoordinates();
return colHeadings.contains(c.row, c.col, currCaptureCell)
|| cornerCell == currCaptureCell;
}
boolean captureByRowHeading() {
if (currCaptureCell == null) { return false; }
return rowHeadingCell(currCaptureCell) || cornerCell == currCaptureCell;
}
Event translate(Event e) {
//get coords of current cell
TableCell cell = (currCaptureCell != null) ?currCaptureCell :currSelectedCell;
int row = cell.getCoordinates().row;
int col = cell.getCoordinates().col;
int currY = (row - topRow) * cellHeight + headingHeight + 2;
int currX = splitters[col] - splitters[leftCol - 1];
//translate event's x and y to cell relative
if (!captureByRowHeading()) {
e.x -= (currX + rowHeadingWidth);
}
if (!captureByHeading()) {
e.y -= currY;
}
return e;
}
void handleColDrag(int x) {
//fix any drag that went off the left side
int shiftLeft = splitters[leftCol-1] + rowHeadingWidth;
if (dragColumn == 0) {
//dragging to change size of header area
rowHeadingWidth = Math.max(0, x);
} else if (x < splitters[dragColumn-1] - shiftLeft) {
x = splitters[dragColumn-1] - shiftLeft;
}
//erase prvious drag line and draw in new position
gg.setColor(getBackground());
gg.setXORMode(Color.black);
gg.drawLine(xDragLast,0, xDragLast, size().height);
gg.drawLine(x, 0, x, size().height);
gg.setColor(Color.black);
gg.setPaintMode();
//save x position of drag line
xDragLast = x;
repaint();
}
/**
* Resizes the specified column so that the right side of the column
* is set to the requested pixel position.
* @param col The column number
* @param rightSide The pixel position of the right side of the column
*/
public /* synchronized */ void resizeColumn(int col, int rightSide) {
int diff = rightSide - splitters[col] + splitters[leftCol-1];
int len = splitters.length;
splitters[col] = rightSide + splitters[leftCol-1];
splitters[col] = Math.max(0, splitters[col]);
for(int i=col+1;i<len;i++) {
splitters[i] += diff;
}
if (autoRedraw) {
redrawAsync();
}
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean mouseUp(Event e, int x, int y) {
if (isDragging) {
//erase drag line
gg.setColor(getBackground());
gg.setXORMode(Color.black);
gg.drawLine(xDragLast, 0, xDragLast, size().height);
gg.setColor(Color.black);
gg.setPaintMode();
//set column width to dragged position
if (dragColumn == 0) {
//changed header size
redrawAsync();
} else {
resizeColumn(dragColumn, xDragLast - rowHeadingWidth);
}
//turn off dragging
xDragLast = -1;
isDragging = false;
return true;
} else {
if (cellHasCapture()) {
translate(e);
return currCaptureCell.mouseEvent(e);
}
}
return false;
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean mouseMove(Event ev, int x, int y) {
boolean isCloseEnough = false;
int shiftLeft = splitters[leftCol-1] - rowHeadingWidth;
if (y < headingHeight && locate(x, y) instanceof Scrollbar && vsb.isVisible()) {
//noop - over vertical scrollbar but still might want to change cursor so
//don't return yet.
} else
// Use resize cursor ?
if (rowHeadingHints.visible && x<rowHeadingWidth+clickMargin && y < headingHeight) {
if ((x < rowHeadingWidth + clickMargin) &&
(x > rowHeadingWidth - clickMargin))
{
isCloseEnough = true;
}
} else if (y<headingHeight) {
// Moving mouse around in header area
// is it close enough to be a column size drag?
for (int i=1; i<splitters.length; i++) {
if ((x < splitters[i] + clickMargin - shiftLeft) &&
(x > splitters[i] - clickMargin - shiftLeft))
{
isCloseEnough = true;
}
}
}
currentCursor = (isCloseEnough? Frame.W_RESIZE_CURSOR : Frame.DEFAULT_CURSOR);
if (currentCursor != frame().getCursorType()) {
frame().setCursor(currentCursor );
}
return false;
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean keyUp(Event e, int key) {
int row, col;
if (currSelectedCell == null) {
row = topRow;
col = 0;
} else {
row = currSelectedCell.row();
col = currSelectedCell.col();
}
if (currSelectedCell != null) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
return false;
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean lostFocus(Event e, Object o) {
if (tabbed) {
requestFocus();
buttonFocus();
tabbed = false;
} else {
//need to deactivate cursor in current cell
if (currSelectedCell != null) {
e.target = currSelectedCell;
e.target = this;
currSelectedCell.deactivateCursor();
}
lostCapture();
}
return false;
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean gotFocus(Event e, Object o) {
//need to activate the cursor in the current cell
if (currSelectedCell != null) {
currSelectedCell.activateCursor();
}
buttonFocus();
return false;
}
private void buttonFocus() {
if (onSolaris) {
button.requestFocus();
}
}
private void shapeButton() {
if (onSolaris) {
button.reshape(0, 0, 1, 1);
}
}
TableCell getUniqueCell(int row, int col) {
if (!cells.contains(row, col)) {
//then we need to use the default cell
TableCell cell = getDefaultCell(row, col).cloneCell();
cell.setDefaultFlag();
return cell;
}
return (TableCell)cells.elementAt(row, col);
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean keyDown(Event e, int key) {
TableCell savedCell = currSelectedCell;
if (savedCell != null)
{
// System.out.println("at the start: " + String.valueOf(savedCell.col()));
}
boolean success = true;
boolean changed = false;
int row, col;
if (eventHandler != null && isToolbarComponent(e.target)) {
return eventHandler.handleToolbarEvent(e);
}
if (currSelectedCell == null) {
row = topRow;
col = 0;
} else {
row = currSelectedCell.row();
col = currSelectedCell.col();
}
int dataRows = -1;
try {
dataRows = dataSource.validDataRowRange(0, row+2);
} catch(DataNotAvailable exc) {}
switch (key) {
case '\n':
if (e.shiftDown()) {
if (currSelectedCell == null) { return false; }
if (!currSelectedCell.loseFocusOnArrow()) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
if (row > 0) {
TableCell newSelection = getUniqueCell(row-1, col);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
}
if (row < getNumberOfRows()-1) {
requestFocus();
TableCell newSelection = getUniqueCell(row+1, col);
sendFocusEvents(currSelectedCell, newSelection);
break;
}
if (row == getNumberOfRows()-1) {
requestFocus();
TableCell newSelection = getUniqueCell(row, col);
sendFocusEvents(currSelectedCell, newSelection);
break;
}
break;
case Event.DOWN:
if (currSelectedCell == null) { return false; }
if (!currSelectedCell.loseFocusOnArrow()) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
if (row < cells.rows()-1 || row < dataRows) {
TableCell newSelection = getUniqueCell(row+1, col);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
case '\t':
// tabbed = true;
//if only tab is pressed
if (e.shiftDown()) {
if (col > 0) {
requestFocus();
TableCell newSelection = getUniqueCell(row, col-1);
sendFocusEvents(currSelectedCell, newSelection);
}
buttonFocus();
break;
}
//if only tab pressed then go right
if (col < getNumberOfCols()-1) {
requestFocus();
TableCell newSelection = getUniqueCell(row, col+1);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
case Event.RIGHT:
if (currSelectedCell == null) { return false; }
if (!currSelectedCell.loseFocusOnArrow()) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
if (col < getNumberOfCols()-1) {
if (savedCell != null)
{
savedCell.setCol(savedCell.col() + 1);
// System.out.println("right: " + String.valueOf(savedCell.col()));
}
TableCell newSelection = getUniqueCell(row, col+1);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
case Event.LEFT:
if (currSelectedCell == null) { return false; }
if (!currSelectedCell.loseFocusOnArrow()) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
if (col > 0) {
if (savedCell != null)
{
savedCell.setCol(savedCell.col() - 1);
// System.out.println("left: " + String.valueOf(savedCell.col()));
}
TableCell newSelection = getUniqueCell(row, col-1);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
case Event.UP:
if (currSelectedCell == null) { return false; }
if (!currSelectedCell.loseFocusOnArrow()) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
if (row > 0) {
TableCell newSelection = getUniqueCell(row-1, col);
sendFocusEvents(currSelectedCell, newSelection);
}
break;
case Event.PGDN:
scrollPageDown();
changed = true;
break;
case Event.PGUP:
scrollPageUp();
changed = true;
break;
case Event.END:
if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
if (e.controlDown()) {
setCurrentCell(getNumberOfRows(),
getNumberOfCols());
} else {
//this call is one relative
setCurrentCell(currSelectedCell.row() + 1,
getNumberOfCols());
}
return true;
}
case Event.HOME:
if (currSelectedCell == null || currSelectedCell.loseFocusOnArrow()) {
if (e.controlDown()) {
//this call is one relative
setCurrentCell(1, 1);
return true;
} else {
//this call is one relative
setCurrentCell(currSelectedCell.row() + 1, 1);
return true;
}
}
default:
if (currSelectedCell != null) {
e.target = currSelectedCell;
return currSelectedCell.keyEvent(e);
}
}
if (changed) redrawAsync();
return success;
}
boolean redrawAgain = false;
Integer redrawAgainCount = new Integer(0);
void setRedrawAgain(boolean value)
{
// System.out.println(Thread.currentThread().getName()
// + " : " + name + " : Entering set...");
// /* synchronized */(redrawAgainCount)
{
// System.out.println(Thread.currentThread().getName()
// + " : " + name + " : Inside set...");
redrawAgain = value;
}
// System.out.println(Thread.currentThread().getName()
// + " : " + name + " : Leaving set...");
}
boolean getRedrawAgain()
{
// System.out.println(Thread.currentThread().getName()
// + " : " + name + " : Entering get...");
// /* synchronized */(redrawAgainCount)
{
// System.out.println(Thread.currentThread().getName()
// + " : " + name + " : Inside get...");
return redrawAgain;
}
}
/**
* The body of the async redraw thread
*/
// Thread redrawer = new Thread(this);
public /* synchronized */ void myWait()
throws java.lang.IllegalMonitorStateException
{
try
{
wait();
}
catch (java.lang.InterruptedException e)
{
}
}
public void run() {
// Thread.currentThread().setName(this.redrawerName);
while(true) {
try {
if (!getRedrawAgain())
{
try
{
myWait();
}
catch (java.lang.IllegalMonitorStateException e)
{
System.out.println(e.getMessage());
Thread.currentThread().yield();
}
}
else
{
Thread.currentThread().yield();
}
} catch(Exception ex) {}
// System.out.println(this.redrawerName
// + " recieved notification.");
setRedrawAgain(false);
redraw(true);
}
}
protected /* synchronized */ void myNotifyAll()
throws java.lang.IllegalMonitorStateException
{
// notifyAll();
redraw(true);
}
/**
* Request for an asynchronous redraw of the Grid. Calling this function can
* greatly increase the efficiency of scrolling and rapid cell movement.
*/
protected void redrawAsync() {
try {
setRedrawAgain(true);
try
{
myNotifyAll();
}
catch (java.lang.IllegalMonitorStateException e)
{
System.out.println(e.getMessage());
}
} catch(Exception ex) {
ex.printStackTrace();
}
}
/**
* Inherited from Component
*/
public /* synchronized */ boolean handleEvent(Event e) {
if (isToolbarComponent(e.target)) {
if (e.target == gotoButton) {
e.arg = gotoTextField.getText();
}
return eventHandler.handleToolbarEvent(e);
}
if (e.target == vsb && e.arg != null) {
switch(e.id) {
case Event.SCROLL_LINE_DOWN:
scrollLineDown(); break;
case Event.SCROLL_PAGE_DOWN:
scrollPageDown(); break;
case Event.SCROLL_PAGE_UP:
scrollPageUp(); break;
case Event.SCROLL_LINE_UP:
scrollLineUp(); break;
case Event.SCROLL_ABSOLUTE:
scrollUpDownAbsolute(vsb.getValue()); break;
}
}
if (e.target == hsb && e.arg != null) {
if (leftCol != hsb.getValue()) {
hsbPosition = leftCol = hsb.getValue();
redrawAsync();
}
}
if (e.target instanceof Scrollbar) {
requestFocus();
}
return super.handleEvent(e);
}
/**
* Scrolls to the specified row.
*/
public void gotoRow(int row) {
this.requestFocus();
if (row < topRow || row > topRow + getPageSize().height - 1) {
scrollUpDownAbsolute(row);
}
setCurrentCell(row,1);
}
/**
* Scrolls up to the specified row.
*/
public /* synchronized */ void scrollUpTo(int newTop) {
newTop = Math.max(0, newTop);
if (newTop != topRow) {
topRow = newTop;
vsbPosition = topRow;
vsb.setValue(vsbPosition);
redrawAsync();
}
}
/**
* Scrolls in the direction required to make the specified row visible.
*/
public void scrollUpDownAbsolute(int row) {
if (row < topRow) {
scrollUpTo(row);
} else {
scrollDownTo(row);
}
}
/**
* Scrolls the Grid one line up
*/
public void scrollLineUp() {
scrollUpTo(topRow - 1);
}
/**
* Scrolls one page up
*/
public void scrollPageUp() {
scrollUpTo(topRow - getPageSize().height + 1);
}
/**
* Scrolls down so the specified row will be visible.
*/
public /* synchronized */ void scrollDownTo(int nextTop) {
int lastRow = cells.rows()-1;
try {
lastRow = Math.max(lastRow,
dataSource.validDataRowRange(0, nextTop));
} catch(DataNotAvailable ex) {}
nextTop = Math.min(nextTop, lastRow);
if (nextTop >= topRow) {
vsbPosition = topRow = nextTop;
vsb.setValue(vsbPosition);
redrawAsync();
}
}
/**
* Scrolls down one line.
*/
public void scrollLineDown() {
scrollDownTo(topRow + 1);
}
/**
* Scrolls down one page.
*/
public void scrollPageDown() {
scrollDownTo(topRow + getPageSize().height - 1);
}
/**
* Gets whether a particular cell is currently being drawn.
*/
public boolean isCellVisible(int row, int col) {
row--;
col--;
boolean changed = false;
int rc = cells.rows();
try {
rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
} catch(DataNotAvailable ex) {}
row = Math.min(rc-1, row);
row = Math.max(0, row);
col = Math.min(col, splitters.length);
col = Math.max(0, col);
if (row < topRow
|| row > topRow + getPageSize().height
|| col+1 < leftCol
|| col+1 > leftCol + getPageSize().width)
{
return false;
}
return true;
}
/**
* Makes the specified cell visible by scrolling as required.
*/
public /* synchronized */ void makeCellVisible(int row, int col) {
row--;
col--;
boolean changed = false;
int rc = cells.rows();
try {
rc = Math.max(rc, dataSource.validDataRowRange(0, row+1)+1);
} catch(DataNotAvailable ex) {}
row = Math.min(rc-1, row);
row = Math.max(0, row);
col = Math.min(col, splitters.length);
col = Math.max(0, col);
// scroll UPWARD
if (row < topRow) {
topRow = row;
vsbPosition = topRow;
vsb.setValue(vsbPosition);
changed = true;
}
// scroll DOWNWARD
if (row > topRow + getPageSize().height - 1) {
topRow = row - getPageSize().height + 1;
vsbPosition = topRow;
vsb.setValue(vsbPosition);
changed = true;
}
// scroll LEFT
col++;
boolean scrollLeft = false;
if (col < leftCol) {
leftCol = (col<1) ?1 :col;
hsbPosition = leftCol;
hsb.setValue(hsbPosition);
scrollLeft = true;
changed = true;
}
// scroll RIGHT
Dimension pgSize = getPageSize();
if (col != leftCol && col > leftCol + pgSize.width - 1) {
hsbPosition = col;
if (pgSize.width > 0) {
leftCol = hsbPosition -= (pgSize.width-1);
}
leftCol = hsbPosition;
hsb.setValue(hsbPosition);
changed = true;
}
if (changed) {
if (scrollLeft) {
redraw(true);
} else {
redrawAsync();
}
}
}
boolean postEvent(int id, int num) {
Event e = new Event(this, id, new Integer(num));
return postEvent(e);
}
Dimension getPageSize() {
Dimension d = size();
int i = leftCol;
if (vsb.isVisible()) { d.width -= vsb.size().width; }
for (;i<splitters.length;i++) {
if (splitters[i] - splitters[leftCol-1] > d.width) {
break;
}
}
d.width = i - leftCol;
d.height -= bottomPanel.size().height;
d.height = (d.height - headingHeight)/cellHeight;
return d;
}
void drawHeadings(int numRowsToDraw) {
//iterate headings and draw them
int r = 0;
MatrixEnumeration e = colHeadings.elements();
TableCell c = null;
int x, w;
int cols = getNumberOfCols();
//iterate the headings and paint each one
while(e.hasMoreElements() || c != null) {
//iterate the cols of the current row
for (int col=leftCol-1; col<cols; col++) {
w = getColumnWidth(col);
while ((c == null || e.currCol() < col) && e.hasMoreElements()) {
c = (TableCell)e.nextElement();
if (e.currCol() < col) {
//keep going till get to correct column
c = null;
}
}
if (e.currCol() == col) {
hints.setHints(c);
c.drawCell(gg, hints);
c = null;
}
if (c != null) {
c = null;
}
}
}
drawRowHeadings(numRowsToDraw);
}
/* synchronized */ void redrawColHeadingCell(int col) {
if (col < leftCol-1 || col >= getNumberOfCols()) {
//col heading not visible so get out now
return;
}
TableCell cell = (TableCell)colHeadings.elementAt(0, col);
hints.setHints(cell);
cell.drawCell(gg, hints);
}
/* synchronized */ void redrawRowHeadingCell(int row) {
if (!rowHeadingHints.visible || !validRow(row)) {
//not drawing row heading so get out quickly
return;
}
//if current cell is heading cell we need to draw it in proper state
if (rowHeadingCell(currCaptureCell) && currCaptureCell.row() == row) {
hints.setHints(currHeadingCell);
currHeadingCell.drawCell(gg, hints);
} else {
TableCell cell = headingCell.cloneCell();
cell.setRow(row);
hints.setHints(cell);
cell.drawCell(gg, hints);
}
}
void drawRowHeadings(int count) {
if (!rowHeadingHints.visible) {
//not drawing row heading so get out quickly
return;
}
TableCell cell = headingCell.cloneCell();
Coordinate c = cell.getCoordinates();
for (int i=0; i<count; i++) {
cell.setRow(i + topRow);
hints.setHints(cell);
cell.drawCell(gg, hints);
}
//if current cell is heading cell we need to draw it in proper state
if (rowHeadingCell(currCaptureCell)) {
hints.setHints(currHeadingCell);
currHeadingCell.drawCell(gg, hints);
}
redrawCornerCell();
}
/* synchronized */ void redrawCornerCell() {
//draw corner cell
hints.setHints(cornerCell);
cornerCell.drawCell(gg, hints);
}
Frame frame() {
Container c = this;
while(!(c instanceof Frame)) {
c = c.getParent();
}
return (Frame)c;
}
//-----------------------------------------------------------------------------
// CellHints methods
//-----------------------------------------------------------------------------
/**
* Adds a CellHint dedicated to a row.
* <p>This fucntion is 0 relative
*/
public void addRowHint(int row, CellHints c) {
row++;
cellAttributes.addElement(row, 0, c);
}
/**
* Adds a CellHint dedicated to a cell.
* <p>This fucntion is 0 relative
*/
public void addCellHint(int row, int col, CellHints c) {
row++;
col++;
cellAttributes.addElement(row, col, c);
}
/**
* Gets a CellHint dedicated to a cell.
* <p>This fucntion is 0 relative
*/
public CellHints getCellHints(int row, int col) {
row++;
col++;
if (cellAttributes.contains(row, col)) {
return (CellHints)cellAttributes.elementAt(row, col);
} else {
return null;
}
}
/**
* Gets a CellHint dedicated to a row.
* <p>This fucntion is 0 relative
*/
public CellHints getRowHints(int row) {
row++;
if (cellAttributes.contains(row, 0)) {
return (CellHints)cellAttributes.elementAt(row, 0);
} else {
return null;
}
}
/**
* Gets a CellHint dedicated to a column.
* <p>This fucntion is 0 relative
*/
public CellHints getColHints(int col) {
//column attributes must be set
col++;
return (CellHints)cellAttributes.elementAt(0, col);
}
/**
* Gets the CellHints for a column heading<p>
* row is zero relative<br>
* col is one relative - with cornercell coord being 0
*/
public CellHints getHeadingHints(int row, int col) {
return (CellHints)headingAttributes.elementAt(row, col);
}
/**
* Gets the cell alignment for the specified cell
*/
public int getCellAlignment(TableCell c) {
CellHints hc = getCellHints(c.row(), c.col());
CellHints hr = getRowHints(c.row());
CellHints h = getColHints(c.col());
return h.cascadeAlignment(hr, hc);
}
/**
* Gets the cell foreground for the specified cell
*/
public Color getCellFG(TableCell c) {
CellHints hc = getCellHints(c.row(), c.col());
CellHints hr = getRowHints(c.row());
CellHints h = getColHints(c.col());
return h.cascadeForeground(hr, hc);
}
/**
* Gets the cell background for the specified cell
*/
public Color getCellBG(TableCell c) {
CellHints hc = getCellHints(c.row(), c.col());
CellHints hr = getRowHints(c.row());
CellHints h = getColHints(c.col());
return h.cascadeBackground(hr, hc);
}
/**
* Gets whether a specified cell is editable according to the CellHints
*/
public boolean getCellEditable(TableCell c) {
CellHints hc = getCellHints(c.row(), c.col());
CellHints hr = getRowHints(c.row());
CellHints h = getColHints(c.col());
return h.cascadeEditable(hr, hc);
}
/**
* Determines whether the specified cell is highlighted
*/
public boolean getCellHighlighted(TableCell c) {
//adjust for all highlight functions being 1 relative
int row = c.row() + 1;
int col = c.col() + 1;
if (c.type() == TableCell.COL_HEADING) {
isColumnSelected(col);
} else if (c == cornerCell) {
return isViewSelected();
} else if (rowHeadingCell(c)) {
return isRowSelected(row) || isCellSelected(row, col);
}
//must be an honest to goodness cell
return isCellSelected(row, col);
}
/**
* Gets the font for the specified cell
*/
public Font getCellFont(TableCell c) {
CellHints hc = getCellHints(c.row(), c.col());
CellHints hr = getRowHints(c.row());
CellHints h = getColHints(c.col());
return h.cascadeFont(hr, hc);
}
/**
* Gets whether the specified cell should be drawn.
*/
public boolean getCellVisibility(TableCell c) {
if (rowHeadingCell(c)) {
return rowHeadingHints.visible;
}
if (c.type() == TableCell.COL_HEADING) {
return getHeadingHints(c.row(), c.col()+1).isVisible();
}
//get hints for cell, row, col and combine
CellHints h = getCellHints(c.row(), c.col());
if (h != null && !h.isVisible()) { return false; }
h = getRowHints(c.row());
if (h != null && !h.isVisible()) { return false; }
//column has to be set
h = getColHints(c.col());
return h.isVisible();
}
//-----------------------------------------------------------------------------
// Selection control variables and member functions
//-----------------------------------------------------------------------------
//ALL OF THESE FUNCTIONS ARE ONE RELATIVE!!!!!!!
/**
* The bit set that defines which cells/rows/cols are selected. <BR>
* bit 0 = corner cell <BR>
* bit 1 - # of cols = columns <BR>
* bit (# of cols) * row + 1 = rows <BR>
* all other bits represent individual cells
*/
BitSet selected = new BitSet();
Coordinate selectionBase = null;
Coordinate selectionLimit = null;;
boolean selectionMade = false;
/**
* Gets whether the specified row is selected
*/
public boolean isRowSelected(int row) {
return selected.get(tx4Sxn(row));
}
/**
* Gets whether the specified cell is selected
*/
public boolean isCellSelected(int row, int col) {
return selected.get(tx4Sxn(row, col));
}
/**
* Gets whether the specified column is selected
*/
public boolean isColumnSelected(int col) {
return selected.get(col);
}
/**
* Gets whether the whole grid is selected
*/
public boolean isViewSelected() { return selected.get(0); }
public void toggleCell(int row, int col) {
if (!isRowSelected(row)) {
toggleBit(tx4Sxn(row, col));
}
}
/**
* Gets a list of the coordinates for all of the selected cells
*/
public Coordinate[] getSelectedCells() {
Vector cells = new Vector();
int cols = getNumberOfCols();
int rows = sxnRows(cols);
for (int row=1;row<rows;row++) {
for (int col=1; col<cols; col++) {
if (selected.get(tx4Sxn(row, col))) {
cells.addElement(new Coordinate(row, col));
}
}
}
Coordinate sxn[] = new Coordinate[cells.size()];
cells.copyInto(sxn);
return sxn;
}
/**
* Gets the row number of the first selected row
* @return The first selected row, -1 if none are selected
*/
public int getFirstSelectedRow() {
int cols = getNumberOfCols();
int total = selected.size();
int row = 1;
for (int index=cols+1; index<total; index+=(cols+1), row++) {
if (selected.get(index)) {
return row;
}
}
return -1;
}
/**
* Gets an array of all of the selected rows
*/
public int[] getSelectedRows() {
int cols = getNumberOfCols();
int total = selected.size();
int srows[] = new int[dataSource.rows()];
int row = 1;
int next = 0;
for (int index=cols+1; index<total; index+=(cols+1), row++) {
if (selected.get(index)) {
srows[next++] = row;
}
}
int sxn[] = new int[next];
System.arraycopy(srows, 0, sxn, 0, next);
return sxn;
}
/**
* Gets an array of all of the selected columns
*/
public int[] getSelectedCols() {
int cols = getNumberOfCols();
int scols[] = new int[cols];
int next = 0;
for (int col=1; col<=cols; col++) {
if (selected.get(col)) {
scols[next-1] = col;
next++;
}
}
int sxn[] = new int[next];
System.arraycopy(scols, 0, sxn, 0, next);
return sxn;
}
/**
* Determines whether the specified row is hightlighted
*/
public boolean isRowSet(int row) {
return selected.get(tx4Sxn(row));
}
/**
* Selects the specified row
*/
public /* synchronized */ void setRow(int row, boolean setTo) {
int bit = tx4Sxn(row);
int cols = getNumberOfCols();
for (int i=0;i<=cols;i++) {
if (setTo) {
selected.set(bit+i);
} else {
selected.clear(bit+i);
}
}
selectionMade = true;
if (autoRedraw) { redrawRow(row); }
}
/**
* Toggles the selection on the specified row.
*/
public /* synchronized */ void toggleRow(int row) {
int bit = tx4Sxn(row);
boolean set = selected.get(bit);
int cols = getNumberOfCols();
for (int i=0;i<=cols;i++) {
if (set) {
selected.clear(bit+i);
} else {
selected.set(bit+i);
}
}
selectionMade = true;
if (autoRedraw) { redrawRow(row); }
}
/**
* Toggles the selection for the specified column
*/
public /* synchronized */ void toggleCol(int col) {
boolean set = selected.get(col);
int cols = getNumberOfCols();
int total = selected.size();
for (int i=col; i<=total; i+=(cols+1)) {
if (set) {
selected.clear(i);
} else {
selected.set(i);
}
}
selectionMade = true;
if (autoRedraw) { redrawAsync(); }
}
/**
* Either clears all cell selections or selects all cells.
*/
public /* synchronized */ void toggleAll() {
if (selected.get(0)) {
//clear all bits
clearAllSelections();
} else {
//set all of them
int total = selected.size();
for (int i=0; i<total; i++) {
selected.set(i);
}
selectionMade = true;
}
if (autoRedraw) { redrawAsync(); }
}
/**
* Unselects all cells.
*/
public /* synchronized */ void clearAllSelections() {
if (selectionMade) {
selectionBase = null;
selectionLimit = null;
selectionMade = false;
selected.xor(selected);
if (autoRedraw) { redrawAsync(); }
}
}
/**
* Sets the cell by which range selections are performed
*/
public void setSelectionBase(int row, int col) {
selectionBase = new Coordinate(row, col);
}
/**
* Determines whether a selection base cell has been set.
*/
public boolean isSelectionBaseSet() {
return selectionBase != null;
}
/**
* Determines if a range of cells are currently selected.
*/
public boolean isRangeSelected() {
return selectionLimit != null;
}
//need to provide for erasing values in cells then make public
void eraseRangeSelection() {
//need to turn autoRedraw off while doing this
setRange(false);
}
/* synchronized */ void setRange(boolean setTo) {
//if value == true then set bits o.w. clear bits
if (selectionBase == null) { return; }
if (selectionLimit == null) {
selectionLimit = selectionBase;
}
int topRow = Math.min(selectionBase.row, selectionLimit.row);
int topCol = Math.min(selectionBase.col, selectionLimit.col);
int bottomRow = Math.max(selectionBase.row, selectionLimit.row);
int bottomCol = Math.max(selectionBase.col, selectionLimit.col);
//need to turn autoRedraw off while doing this
boolean auto = autoRedraw;
autoRedraw = false;
//check for two rows defining range
if (selectionBase.col == 0 && selectionLimit.col ==0) {
//two row selections made - this is easy case
for (int row=topRow; row<=bottomRow; row++) {
setRow(row, setTo);
}
}
autoRedraw = auto;
if (autoRedraw) { redrawAsync(); }
}
/**
* Clears all selections
*/
public void clearRangeSelection() {
eraseRangeSelection();
selectionBase = null;
selectionLimit = null;
}
/**
* Selects the range that spans from the currently selected base cell to
* the specified row and column.
*/
public /* synchronized */ void selectRange(int limitRow, int limitCol) {
//if no base, then we do not select any rows
if (selectionBase == null) {
selectionBase = new Coordinate(limitRow, limitCol);
}
boolean auto = autoRedraw;
autoRedraw = false;
//erase old range and draw new one
eraseRangeSelection();
selectionLimit = new Coordinate(limitRow, limitCol);
setRange(true);
autoRedraw = auto;
if (autoRedraw) { redrawAsync(); }
}
/**
* Selects a range of cells and sets the base for future selections
*/
public void selectRange(int baseRow, int baseCol, int limitRow, int limitCol) {
//if previous selection erase
clearRangeSelection();
//create a new range base
selectionBase = new Coordinate(baseRow, baseCol);
selectRange(limitRow, limitCol);
}
final void toggleBit(int bit) {
selectionMade = true;
if (selected.get(bit)) {
selected.clear(bit);
} else {
selected.set(bit);
}
}
//1 relative
final int tx4Sxn(int row, int col) {
return tx4Sxn(row) + col;
}
//1 relative
final int tx4Sxn(int row) {
int cols = getNumberOfCols();
return (cols+1) * (row);
}
final int sxnRows(int cols) {
return (int)Math.ceil(selected.size() / (cols + 1f));
}
}